﻿using System;
using System.Collections.Generic;
using System.Security.Principal;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace iESELibrary.DESCrypto.Vault
{
	public class SidKey : IDisposable
	{
		#region Constants
		private static readonly byte[] ODD_PARITY = new byte[]{
			1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
			16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
			32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
			49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
			64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
			81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
			97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
			112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
			128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
			145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
			161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
			176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
			193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
			208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
			224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
			241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254
};
		#endregion

		#region Variables
		private bool disposed = false;
		private UInt64 rid;
		private byte[] sidKey1;
		private byte[] sidKey2;
		#endregion

		#region Properties
		public byte[] SidKey1
		{
			get
			{
				return this.sidKey1;
			}
		}

		public byte[] SidKey2
		{
			get
			{
				return this.sidKey2;
			}
		}

		#endregion

		#region Constructors
		/// <summary>
		/// Initiates SidKey(s) object with account objectSid
		/// </summary>
		/// <param name="objectSid">Account object Security-Identifier</param>
		public SidKey(byte[] objectSid)
		{
			GenerateRID(objectSid);
			GenerateRidKeys(this.rid);
		}
		#endregion

		#region Enums
		#endregion

		#region Private Methods
		private void GenerateRidKeys(UInt64 rid)
		{
			//Key1
			byte[] key1 = new byte[8];
			key1[0] = (byte)(rid & 0xFF);
			key1[1] = (byte)((rid >> 8) & 0xFF);
			key1[2] = (byte)((rid >> 16) & 0xFF);
			key1[3] = (byte)((rid >> 24) & 0xFF);
			key1[4] = key1[0];
			key1[5] = key1[1];
			key1[6] = key1[2];

			this.sidKey1 = ConvertKey(key1);

			//Key2
			byte[] key2 = new byte[8];
			key2[0] = key1[3];
			key2[1] = key1[0];
			key2[2] = key1[1];
			key2[3] = key1[2];
			key2[4] = key1[3];
			key2[5] = key1[0];
			key2[6] = key1[1];

			this.sidKey2 = ConvertKey(key2);
		}

		private byte[] ConvertKey(byte[] key)
		{
			byte[] resultKey = new byte[8];
			resultKey[0] = (byte)(key[0] >> 0x01);
			resultKey[1] = (byte)(((key[0] & 0x01) << 6) | (key[1] >> 2));
			resultKey[2] = (byte)(((key[1] & 0x03) << 5) | (key[2] >> 3));
			resultKey[3] = (byte)(((key[2] & 0x07) << 4) | (key[3] >> 4));
			resultKey[4] = (byte)(((key[3] & 0x0F) << 3) | (key[4] >> 5));
			resultKey[5] = (byte)(((key[4] & 0x1F) << 2) | (key[5] >> 6));
			resultKey[6] = (byte)(((key[5] & 0x3F) << 1) | (key[6] >> 7));
			resultKey[7] = (byte)(key[6] & 0x7F);

			for (int i=0; i<8; i++)
			{
				resultKey[i] = (byte)(resultKey[i] << 0x1);
				resultKey[i] = ODD_PARITY[resultKey[i]];
			}

			return resultKey;
		}

		private void GenerateRID(byte[] objectSid)
		{
			try
			{
				//rewrite this part G$
				string hex = BitConverter.ToString(objectSid).Replace("-", String.Empty).Substring(48);

				//byte[] ridBytes = new byte[objectSid.Length - 24];
				//System.Buffer.BlockCopy(objectSid, 24, ridBytes, 0, ridBytes.Length);

				this.rid = Convert.ToUInt64(hex, 16);
			}
			catch(Exception eX)
			{

			}
		}
		#endregion

		#region IDisposable Members
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!this.disposed)
			{
				if (disposing)
				{

				}

				this.disposed = true;
			}
		}
		#endregion
	}
}
